﻿/*/
 * Fuzzy Number Calculator v 1.0
 * By Ahmed Ezz.
 *  Student at Final year Computer & system Engineering
 *  Al-Azhar University
 *  -- last modification at: 24/10/2008
/*/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using System.Windows.Forms;

namespace FuzzyNumCalc
{
    public partial class frmMainCalc : Form
    {
        // this is an alternative way of setting all operations
        // supported by this application
        enum FuzzyOperation
        {
            Addition,
            Subtraction,
            Multiplication,
            Division,
            NOP                // no operation
        }

        // general variables for the calculator
        FuzzyNumber num1 = new FuzzyNumber();        
        FuzzyNumber num2 = new FuzzyNumber();
        FuzzyNumber result = new FuzzyNumber();
        FuzzyOperation fuzOp;

        // ----------- old code
        //bool num1Active = false;
        //bool num2Active = false;        
        //int clickCounts;
        // --------------------

        // traditional constructor
        public frmMainCalc()
        {
            InitializeComponent();
        }

        private void frmMainCalc_Load(object sender, EventArgs e)
        {
            // --------------- old code
            //EnableNumbers(false);
            //EnableOperations(false);
            //clickCounts = 0;
            // ------------------------

            // default operation is : none at the program start
            fuzOp = FuzzyOperation.NOP;

            // TEST Data and test operation is summation
            num1.a = 15;
            num1.b = 25;
            num1.c = 35;
            num2.a = 10;
            num2.b = 12;
            num2.c = 15;
            result.a = num1.a + num2.a;
            result.b = num1.b + num2.b;
            result.c = num1.c + num2.c;
            //

            // show the result of the data in labels
            lblFN1.Text = "NUM 1: [ " + num1.a + ", " + num1.b + ", " + num1.c + " ]";
            lblFN2.Text = "NUM 2: [ " + num2.a + ", " + num2.b + ", " + num2.c + " ]";
            lblResult.Text = "Result: [ " + result.a + ", " + result.b + ", " + result.c + " ]";
        }

        #region Old Code
        /*
        private void EnableOperations(bool enable)
        {
            btnAdd.Enabled = enable;
            btnSub.Enabled = enable;
            btnMul.Enabled = enable;
            btnDiv.Enabled = enable;
            //btnEqual.Enabled = enable;
        }
        */

        /*
        private void EnableNumbers(bool enable)
        {
            btn0.Enabled = enable;
            btn1.Enabled = enable;
            btn2.Enabled = enable;
            btn3.Enabled = enable;
            btn4.Enabled = enable;
            btn5.Enabled = enable;
            btn6.Enabled = enable;
            btn7.Enabled = enable;
            btn8.Enabled = enable;
            btn9.Enabled = enable;
            //btnDot.Enabled = enable;
        }
        */
        #endregion

        private void btnFN1_Click(object sender, EventArgs e)
        {
            #region OLD CODE
            /*
            if (num1Active)
            {
                btnFN2.Enabled = false;
                //EnableNumbers(true);
                return;
            }
            
            //EnableNumbers(true);
            num1Active = true;
            clickCounts = 0;
            btnFN2.Enabled = false;
            */
            #endregion

            // try getting the first operand fuzzy number
            // from the 3 text box.
            // if any error occur, tell the user about this error
            try
            {
                num1.a = Convert.ToInt32(txtFN1a.Text);
                num1.b = Convert.ToInt32(txtFN1b.Text);
                num1.c = Convert.ToInt32(txtFN1c.Text);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            // show the first fuzzy number operand in textual format
            lblFN1.Text = "NUM 1: [ " + num1.a + ", " + num1.b + ", " + num1.c + " ]";
        }

        private void btnFN2_Click(object sender, EventArgs e)
        {
            #region OLD CODE
            /*
            if (num2Active)
            {
                btnFN1.Enabled = false;
                //EnableNumbers(true);
                return; 
            }

            //EnableNumbers(true);
            num2Active = true;
            clickCounts = 0;
            btnFN1.Enabled = false;
            */
            #endregion

            // try getting the second operand fuzzy number
            // from the 3 text box.
            // if any error occur, tell the user about this error
            try
            {
                num2.a = Convert.ToInt32(txtFN2a.Text);
                num2.b = Convert.ToInt32(txtFN2b.Text);
                num2.c = Convert.ToInt32(txtFN2c.Text);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            // show the second fuzzy number operand in textual format
            lblFN2.Text = "NUM 2: [ " + num2.a + ", " + num2.b + ", " + num2.c + " ]";
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            // save this current fuzzy operation to be addition
            fuzOp = FuzzyOperation.Addition;
            // call the function to calculate and display the result
            btnEqual_Click(sender, e);
        }

        private void btnSub_Click(object sender, EventArgs e)
        {
            // save this current fuzzy operation to be Subtraction
            fuzOp = FuzzyOperation.Subtraction;
            // call the function to calculate and display the result
            btnEqual_Click(sender, e);
        }

        private void btnMul_Click(object sender, EventArgs e)
        {
            // save this current fuzzy operation to be Multiplication
            fuzOp = FuzzyOperation.Multiplication;
            // call the function to calculate and display the result
            btnEqual_Click(sender, e);
        }

        private void btnDiv_Click(object sender, EventArgs e)
        {
            // save this current fuzzy operation to be Division
            fuzOp = FuzzyOperation.Division;
            // call the function to calculate and display the result
            btnEqual_Click(sender, e);
        }

        #region OLD CODE
        /*
        private void btnNum_Click(object sender, EventArgs e)
        {
            clickCounts++;

            if (clickCounts >= 3)
            {
                btnFN1.Enabled = true;
                btnFN2.Enabled = true;
                //EnableOperations(true);
                //EnableNumbers(false);
                //return;
            }

            if (num1Active)
            {
                if (clickCounts == 1)
                    num1.a = Convert.ToInt32((((Button)sender).Text));
                if (clickCounts == 2)
                    num1.b = Convert.ToInt32((((Button)sender).Text));
                if (clickCounts == 3)
                {
                    num1.c = Convert.ToInt32((((Button)sender).Text));
                    clickCounts = 0;
                    num1Active = false;
                }

                return;
            }

            if (num2Active)
            {
                if (clickCounts == 1)
                    num2.a = Convert.ToInt32((((Button)sender).Text));
                if (clickCounts == 2)
                    num2.b = Convert.ToInt32((((Button)sender).Text));
                if (clickCounts == 3)
                {
                    num2.c = Convert.ToInt32((((Button)sender).Text));
                    clickCounts = 0;
                    num2Active = false;
                }

                return;
            }
        }
        */
        #endregion

        private void btnEqual_Click(object sender, EventArgs e)
        {
            // insure that we will continue with a valid operation
            if (fuzOp == FuzzyOperation.NOP)
            {
                MessageBox.Show("Please Choose an Operation first!");
                return;
            }

            // perform the calculation and save the result

            if (fuzOp == FuzzyOperation.Addition)
            {
                result.a = num1.a + num2.a;
                result.b = num1.b + num2.b;
                result.c = num1.c + num2.c;
            }

            if (fuzOp == FuzzyOperation.Subtraction)
            {
                result.a = num1.a - num2.a;
                result.b = num1.b - num2.b;
                result.c = num1.c - num2.c;
            }

            if (fuzOp == FuzzyOperation.Multiplication)
            {
                result.a = num1.a * num2.a;
                result.b = num1.b * num2.b;
                result.c = num1.c * num2.c;
            }

            if (fuzOp == FuzzyOperation.Division)
            {
                try
                {
                    result.a = num1.a / num2.a;
                    result.b = num1.b / num2.b;
                    result.c = num1.c / num2.c;
                }
                catch (DivideByZeroException ex)
                {
                }
            }

            // show the result in textual format in label
            lblResult.Text = "Result: [ " + result.a + ", " + result.b + ", " + result.c + " ]";

            // refresh graphical drawing to redraw with the new data
            pbViewer.Refresh();            
        }

        private void btnExit_Click(object sender, EventArgs e)
        {
            Close();
        }

        /// <summary>
        /// Draw A Trianlge for the surface passing it's graphics 
        /// context and 3 points that construct it
        /// and color of the forground brush hatching.
        /// </summary>
        /// <param name="g">surface context</param>
        /// <param name="a">first triangle point</param>
        /// <param name="b">second triangle point</param>
        /// <param name="c">third triangle point</param>
        /// <param name="clr">color of the foreground hatching</param>
        void DrawTriangle(ref Graphics g, float a, float b, float c, Color clr)
        {
            // our surface area represented by a picture box
            // our scaling system do not start drawing from
            // far left to far right, but instead skip
            // some space around drawing area like WORD program does

            // add left pads (skip 25 pixel from the left)
            a += 25;
            b += 25;
            c += 25;
            
            // create our brush that will fill the triangle
            HatchBrush br = new HatchBrush(
                HatchStyle.ForwardDiagonal, clr, Color.White);

            // our triangle is just 3 points represent a path
            /*
             * 
             *           y = 25
             *           
             *                b.
             *               / | \
             *              /  |  \ 
             *             /   |   \
             *            /____|____\
             *            a          c
             *            
             *           y = 100
             */
            GraphicsPath path = new GraphicsPath();
            path.AddLine(new PointF(a, 100), new PointF(c, 100));
            path.AddLine(new PointF(a, 100), new PointF(b, 25));
            path.AddLine(new PointF(b, 25), new PointF(c, 100));
            path.AddLine(new PointF(b, 100), new PointF(b, 100));
            g.FillPath(br, path);
            br.Dispose();

            // draw the triangle borders
            g.DrawLine(Pens.Black, new PointF(a, 100),
                                  new PointF(c, 100));
            g.DrawLine(Pens.Black, new PointF(a, 100),
                                  new PointF(b, 25));
            g.DrawLine(Pens.Black, new PointF(b, 25),
                                  new PointF(c, 100));
            g.DrawLine(Pens.Black, new PointF(b, 100),
                                  new PointF(b, 25));
        }

        private void pbViewer_Paint(object sender, PaintEventArgs e)
        {
            // this function draw a specified fuzzy number in the
            // background of the picture box and apply hatched brush

            // get the context of the picture box area
            Graphics gr = e.Graphics;

            // calculate the min and max number for graphics scaling
            int maxX = Math.Max(result.c, Math.Max(num1.c, num2.c));
            int minX = Math.Min(result.a, Math.Min(num1.a, num2.a));

            // constants for our scaling system
            float virtual_diff      = maxX - minX;
            float virtual_splitSize = virtual_diff / 10;
            float real_diff         = 220;
            float real_splitSize    = real_diff / 10;
            float real_unity = real_splitSize / virtual_splitSize;
            float a,b,c;            

            // Draw Numbers & Result if visible counting for the
            // Scaling Constant and scaling calculation.
            // (if any problem understanding the drawing
            //  please contact me : aeamg@yahoo.co.uk)

            //
            // Draw Num 1
            //            
            if (chkFN1.Checked)   // if number 1 is visible
            {
                a = ((float)num1.a - minX) * real_unity;
                b = ((float)num1.b - minX) * real_unity;
                c = ((float)num1.c - minX) * real_unity;
                DrawTriangle(ref gr, a, b, c, Color.Green);
            }

            //
            // Draw Num 2
            //
            if (chkFN2.Checked)
            {
                a = ((float)num2.a - minX) * real_unity;
                b = ((float)num2.b - minX) * real_unity;
                c = ((float)num2.c - minX) * real_unity;
                DrawTriangle(ref gr, a, b, c, Color.Red);
            }

            //
            // Draw Result
            //
            if (chkResult.Checked)
            {
                a = ((float)result.a - minX) * real_unity;
                b = ((float)result.b - minX) * real_unity;
                c = ((float)result.c - minX) * real_unity;
                DrawTriangle(ref gr, a, b, c, Color.Blue);
            }

            // draw y axis
            gr.DrawLine(Pens.Black, new Point(20, 25),
                                   new Point(20,100));

            // draw x axis
            gr.DrawLine(Pens.Black, new Point(25, 100), 
                                    new Point(250, 100));

            // draw data at horizontal line scale
            for (int i = 0; i < 10; i++)
            {                
                gr.DrawString((minX + (int)(i * virtual_splitSize)).ToString(), Font, Brushes.Red, (20 + (25 * i)), 105);
            }

            // draw data at vertical line scale
            gr.DrawString("1", Font, Brushes.Red, 5, 20);
            gr.DrawString(".7", Font, Brushes.Red, 5, 40);
            gr.DrawString(".5", Font, Brushes.Red, 5, 60);
            gr.DrawString(".2", Font, Brushes.Red, 5, 80);
        }

        private void chk_CheckedChanged(object sender, EventArgs e)
        {
            // some of the numbers has been hidden or showed
            // so refersh the drawing area
            pbViewer.Refresh();
        }
    }

    /// <summary>
    /// Simple Fuzzy Number Class
    /// represent fuzzy number by 3 numeric values.
    /// </summary>
    class FuzzyNumber
    {
        public FuzzyNumber()
        {
            a = b = c = 0;
        }

        public int a, b, c;
    }
}
